home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / muds / mordor_2.000 / mordor_2 / src / io.c < prev    next >
C/C++ Source or Header  |  1995-06-21  |  26KB  |  1,055 lines

  1. /*
  2.  * IO.C:
  3.  *
  4.  *    Socket input/output/establishment functions.
  5.  *
  6.  *    Copyright (C) 1991, 1992, 1993 Brett J. Vickers
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include <sys/signal.h>
  15. #include <sys/wait.h>
  16. #include <sys/time.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include <netdb.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include "mstruct.h"
  23. #include "mextern.h"
  24.  
  25. #define buflen(a,b,c)    (a-b + (a<b ? c:0))
  26. #define saddr        addr.sin_addr.s_addr
  27. #define MAXPLAYERS    80
  28.  
  29. typedef struct wq_tag {
  30.     int        fd;
  31.     struct wq_tag    *next_tag;
  32. } wq_tag;
  33.  
  34. int                Numplayers;
  35. int                Numwaiting;
  36. int                Deadchildren;
  37. static wq_tag            *First_wait;
  38. static int            Waitsock;
  39. static fd_set            Sockets;
  40. extern int            Port;
  41.  
  42. /**********************************************************************/
  43. /*                sock_init                  */
  44. /**********************************************************************/
  45.  
  46. /* This function initializes the socket that is used to accept new  */
  47. /* connections on.                            */
  48.  
  49. void sock_init(port, debug)
  50. int    port;
  51. int    debug;
  52. {
  53.     struct sockaddr_in     addr;
  54.     struct linger        ling;
  55.     int             n, i;
  56.     extern char        report;
  57.  
  58.     if(debug) {
  59.         FD_SET(0, &Sockets);
  60.         FD_SET(1, &Sockets);
  61.         FD_SET(2, &Sockets);
  62.     }
  63.     signal(SIGPIPE, SIG_IGN);
  64.     signal(SIGTERM, SIG_IGN);
  65.     signal(SIGCHLD, child_died);
  66.  
  67.     Tablesize = getdtablesize();
  68.     if (Tablesize > PMAX){
  69.         Tablesize = PMAX;
  70.         logf("Tablesize greater than PMAX\n");
  71.     }
  72.     Waitsock = socket(AF_INET, SOCK_STREAM, 0);
  73.     if(Waitsock < 0)
  74.         exit(-1);
  75.     FD_SET(Waitsock, &Sockets);
  76.  
  77.     addr.sin_addr.s_addr = INADDR_ANY;
  78.     addr.sin_port = htons(port);
  79.  
  80.     if (report){
  81.        i = 1;
  82.         setsockopt(Waitsock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
  83.     }
  84.        
  85.     n = bind(Waitsock, (struct sockaddr *) &addr, sizeof(addr));
  86.     if(n < 0)
  87.         exit(-1);
  88.  
  89.     ling.l_onoff = ling.l_linger = 0;
  90.     setsockopt(Waitsock, SOL_SOCKET, SO_LINGER, (char *)&ling,
  91.            sizeof(struct linger));
  92.  
  93.     listen(Waitsock, 5);
  94.  
  95.     i=1;
  96.     ioctl(Waitsock, FIONBIO, &i);
  97. }
  98.  
  99. /**********************************************************************/
  100. /*                sock_loop                  */
  101. /**********************************************************************/
  102.  
  103. /* This function is the main loop of the entire program.  It constantly */
  104. /* checks for new input, outputs players' output buffers, handles the   */
  105. /* players' commands and updates the game.                */
  106.  
  107. void sock_loop()
  108. {
  109.     while(1) {
  110.         if(Deadchildren) reap_children();
  111.         io_check();
  112.         output_buf();
  113.         handle_commands();
  114.         update_game();
  115.     }
  116. }
  117.  
  118. /**********************************************************************/
  119. /*                io_check                  */
  120. /**********************************************************************/
  121.  
  122. /* This function takes a look at all the sockets that are being used at */
  123. /* the time, and determines which ones have input waiting on them.  The */
  124. /* ones that do call accept_input to have their input buffers updated.  */
  125. /* If the wait socket indicates input is ready to read, that means a    */
  126. /* new connection to the game must be accepted.             */
  127.  
  128. int io_check()
  129. {
  130.     fd_set            sockcheck;
  131.     short            rtn=0, i;
  132.     static struct timeval    t = {0L, 75000L};
  133.  
  134.     sockcheck = Sockets;
  135. /*    t.tv_usec = T_USEC; */
  136. /*    t.tv_sec = 0;        */
  137.     t.tv_usec = 75000L;
  138.     if(select(Tablesize, &sockcheck, 0, 0, &t) > 0) {
  139.         for(i=0; i<Tablesize; i++) {
  140.             if(FD_ISSET(i, &sockcheck)) {
  141.                 if(i != Waitsock)
  142.                     rtn |= accept_input(i);
  143.                 else
  144.                     accept_connect();
  145.             }
  146.         }
  147.     }
  148.  
  149.     return(rtn);
  150. }
  151.  
  152. /**********************************************************************/
  153. /*                accept_connect                  */
  154. /**********************************************************************/
  155.  
  156. /* This function accepts a new connection on the wait socket so that a  */
  157. /* new player can begin playing.  The player's iobuf structure is init- */
  158. /* ialized and a spot is marked in the player and socket arrays for the */
  159. /* player.                                */
  160.  
  161. void accept_connect()
  162. {
  163.     int            len, fd, i=1, pid;
  164.     iobuf            *io;
  165.     extra            *extr;
  166.     struct linger        ling;
  167.     struct sockaddr_in    addr;
  168.     char            *inetname(), path[127], 
  169.                 port1str[10], port2str[10];
  170.  
  171.     addr.sin_family = AF_INET;
  172.     addr.sin_port = htons(Port);
  173.     addr.sin_addr.s_addr = INADDR_ANY;
  174.  
  175.     len = sizeof(struct sockaddr_in);
  176.     fd = accept(Waitsock, (struct sockaddr *) &addr, &len);
  177.     if (fd < 0)
  178.         merror("accept_connect", FATAL);
  179.  
  180.     ioctl(fd, FIONBIO, &i);
  181.  
  182.     ling.l_onoff = ling.l_linger = 0;
  183.     setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&ling,
  184.            sizeof(struct linger));
  185.  
  186.     io = (iobuf *)malloc(sizeof(iobuf));
  187.     extr = (extra *)malloc(sizeof(extra));
  188.     if(!io || !extr) 
  189.         merror("accept_connect", FATAL);
  190.  
  191.     Ply[fd].io = io;
  192.     Ply[fd].ply = 0;
  193.     Ply[fd].extr = extr;
  194.  
  195.     zero(extr, sizeof(extra));
  196.     zero(io, sizeof(iobuf));
  197.     io->ltime = time(0);
  198.     io->intrpt = 1;
  199.  
  200.     strcpy(io->address, inetname(addr.sin_addr));
  201.  
  202.     pid = vfork();
  203.     if(!pid) {
  204.         sprintf(path, "%s/auth", BINPATH);
  205.         sprintf(port1str, "%d", ntohs(addr.sin_port));
  206.         sprintf(port2str, "%d", Port);
  207.         execl(path, "auth", io->address, port1str, port2str, 0);
  208.         exit(0);
  209.     }
  210.     else {
  211.         strcpy(io->userid, "unknown");
  212.         io->lookup_pid = pid;
  213.     }
  214.  
  215.     FD_SET(fd, &Sockets);
  216.  
  217.     if(Numplayers > Tablesize-2) {
  218.         print(fd, "Game full.  Try again later.\n");
  219.         disconnect(fd);
  220.         return;
  221.     }
  222.  
  223.     else if(Numplayers >= MAXPLAYERS &&
  224.         ((unsigned)(ntohl(saddr))>>24) != 127) {
  225.         if(Numwaiting > MAXPLAYERS) {
  226.             write(fd, "Queue full.\n\r", 13);
  227.             disconnect(fd);
  228.             return;
  229.         }
  230.         add_wait(fd);
  231.         RETURN(fd, waiting, 1);
  232.     }
  233.  
  234.     init_connect(fd);
  235. }
  236.  
  237. /************************************************************************/
  238. /*                init_connect                */
  239. /************************************************************************/
  240.  
  241. /* This function sets up the player using the fd'th input socket.    */
  242.  
  243. void init_connect(fd)
  244. int    fd;
  245. {
  246.     int        i;
  247.  
  248.     /*************************************************************/
  249.     /* The following lines must be left intact as part of the    */
  250.     /* copyright agreement.                         */
  251.     /*************************************************************/
  252.     print(fd, "\nMordor v2.5 Beta (C) 1992, 1995");
  253.     print(fd, "\nProgrammed by Brett J. Vickers");
  254.     print(fd, "\nEnhancements by Steve Smith and Brooke Paul");
  255.     /*************************************************************/
  256.     /*************************************************************/
  257.  
  258.     Ply[fd].io->intrpt |= 2;
  259.     Numplayers++;
  260.  
  261.     if((i = locked_out(fd)) > 1) {
  262.         print(fd, "\nA password is required to play from that site.");
  263.         print(fd, "\nPlease enter site password: ");
  264.         output_buf();
  265.         RETURN(fd, login, 0);
  266.     }
  267.     else if(i) {
  268.         disconnect(fd);
  269.         return;
  270.     }
  271.  
  272.     Ply[fd].io->ltime = time(0);
  273.     print(fd, "\n\nPlease enter name: ");
  274.     output_buf();
  275.     RETURN(fd, login, 1);
  276.  
  277. }
  278.  
  279. /************************************************************************/
  280. /*                locked_out                */
  281. /************************************************************************/
  282.  
  283. /* This function determines if the player on socket number, fd, is on    */
  284. /* a site that is being locked out.  If the site is password locked,    */
  285. /* then 2 is returned.  If it's completely locked, 1 is returned.  If    */
  286. /* it's not locked out at all, 0 is returned.                */
  287.  
  288. int locked_out(fd)
  289. int     fd;
  290. {
  291.     int    i;
  292.  
  293.     for(i=0; i<Numlockedout; i++) {
  294.         if(!addr_equal(Lockout[i].address, Ply[fd].io->address))
  295.             continue;
  296.  
  297.         if(Lockout[i].password[0]) {
  298.             strcpy(Ply[fd].extr->tempstr[0], Lockout[i].password);
  299.             return 2;
  300.         }
  301.         else {
  302.             write(fd, "\n\rYour site is locked out.\n\r", 28);
  303.             return 1;
  304.         }
  305.     }
  306.  
  307.     return 0;
  308. }
  309.  
  310. /************************************************************************/
  311. /*                addr_equal                */
  312. /************************************************************************/
  313.  
  314. /* This function determines if two internet addresses are equal and    */
  315. /* allows for wild-cards.                        */
  316.  
  317. int addr_equal(str1, str2)
  318. char    *str1;
  319. char    *str2;
  320. {
  321.  
  322.     while(*str1 && *str2) {
  323.         if(*str1 == '*') {
  324.             while(*str2 != '.' && *str2) str2++;
  325.             str1++;
  326.             continue;
  327.         }
  328.         else if(*str1 != *str2)
  329.             return(0);
  330.         str1++; str2++;
  331.     }
  332.  
  333.     if(!*str1 && !*str2) return(1);
  334.     else return(0);
  335. }
  336.  
  337. /**********************************************************************/
  338. /*                accept_input                  */
  339. /**********************************************************************/
  340.  
  341. /* This function is called when a player's socket indicates that there */
  342. /* is input waiting.  The socket is read from, and the input is copied */
  343. /* into that player's input buffer.  If the last character entered is  */
  344. /* a carriage return, then the player's interrupt flag is set high.    */
  345.  
  346. int accept_input(fd)
  347. int    fd;
  348. {
  349.     char     buf[128], lastchar;
  350.     int     i, n, prev, itail, ihead;
  351.  
  352.     n = read(fd, buf, 127);
  353.  
  354.     if(n<=0)
  355.         Ply[fd].io->commands = -1;    /* Connection dropped */
  356.  
  357.     else {
  358.         ihead = Ply[fd].io->ihead;
  359.         lastchar = 0;
  360.         itail = Ply[fd].io->itail;
  361.         for(i=0; i<n; i++) {
  362.             if(buf[i] > 31 || (buf[i] == '\n' && lastchar != '\r')
  363.                 || buf[i] == '\r' || buf[i] == '\b') {
  364.                 lastchar = buf[i];
  365.                 if(buf[i] == '\r') buf[i] = '\n';
  366.                 if(buf[i] == '\n') Ply[fd].io->commands++;
  367.                 else if(buf[i] == '\b' && ihead != itail) {
  368.                     prev = ihead-1 < 0 ? IBUFSIZE-1:ihead-1;
  369.                     if(Ply[fd].io->input[prev] == '%')
  370.                         ihead -= 2;
  371.                     else
  372.                         ihead--;
  373.                     if(ihead < 0)
  374.                         ihead = IBUFSIZE + ihead;
  375.                     continue;
  376.                 }
  377.                 else if(buf[i] == '\b') continue;
  378.                 Ply[fd].io->input[ihead] = buf[i];
  379.                 ihead = (ihead + 1) % IBUFSIZE;
  380.                 if(ihead == itail)
  381.                     itail = (itail + 1) % IBUFSIZE;
  382.                 if(buf[i] == '%') {
  383.                     Ply[fd].io->input[ihead] = buf[i];
  384.                     ihead = (ihead + 1) % IBUFSIZE;
  385.                     if(ihead == itail)
  386.                         itail = (itail + 1) % IBUFSIZE;
  387.                 }
  388.             }
  389.         }
  390.         Ply[fd].io->ihead = ihead;
  391.         Ply[fd].io->itail = itail;
  392.         Ply[fd].io->ltime = time(0);
  393.         if(buf[n-1] == '\n' || buf[n-1] == '\r')
  394.             Ply[fd].io->intrpt |= 1;
  395.         else
  396.             Ply[fd].io->intrpt &= ~1;
  397.     }
  398.  
  399.     return(0);
  400. }
  401.  
  402. /**********************************************************************/
  403. /*                output_buf                  */
  404. /**********************************************************************/
  405.  
  406. /* This function outputs the contents of all players' buffers when that  */
  407. /* player is able to be interrupted, or when that player's output buffer */
  408. /* has reached a specific high-water mark (75% of buffer size).          */
  409.  
  410. void output_buf()
  411. {
  412.     char    str[20], *pstr;
  413.     int     i, n;
  414.     int    otail, ohead;
  415.  
  416.     for(i=0; i<Tablesize; i++) {
  417.         if(FD_ISSET(i, &Sockets) && Ply[i].io) {
  418.             otail = Ply[i].io->otail;
  419.             ohead = Ply[i].io->ohead;
  420.             if(ohead == otail)
  421.                 continue;
  422.             if(Ply[i].io->commands == -1) {
  423.                 disconnect(i);
  424.                 continue;
  425.             }
  426.             if(Ply[i].io->intrpt & 1) {
  427.                 if(Ply[i].ply)
  428.                     if(Ply[i].ply->fd > -1 && 
  429.                        F_ISSET(Ply[i].ply, PNOCMP)) {
  430.                         n = write(i, "\n\r", 2);
  431.                         if(Spy[i] > -1)
  432.                             write(Spy[i], "\n\r", 2);
  433.                     }
  434.                 n = write(i, &Ply[i].io->output[otail], 
  435.                  ohead>otail ? ohead-otail:OBUFSIZE-otail);
  436.                 if(Spy[i] > -1) write(Spy[i], 
  437.                  &Ply[i].io->output[otail], 
  438.                  ohead>otail ? ohead-otail:OBUFSIZE-otail);
  439.                 if(otail > ohead) {
  440.                     n+= write(i, Ply[i].io->output, ohead);
  441.                     if(Spy[i] > -1) 
  442.                     write(Spy[i], Ply[i].io->output, ohead);
  443.                 }
  444. /*
  445.                 if(n < buflen(ohead, otail, OBUFSIZE))
  446.                     merror("output_buf", NONFATAL);
  447. */
  448.                 otail = ohead;
  449.                 Ply[i].io->otail = otail;
  450.                 if(Ply[i].ply) {
  451.                     pstr = ply_prompt(Ply[i].ply);
  452.                     n = write(i, pstr, strlen(pstr));
  453.                     if(Spy[i] > -1)
  454.                         write(Spy[i],pstr,strlen(pstr));
  455.                 }
  456.             }
  457.             if(buflen(ohead, otail, OBUFSIZE) > (OBUFSIZE*3)/4) {
  458.                 n = write(i, &Ply[i].io->output[otail], 
  459.                  ohead>otail ? ohead-otail:OBUFSIZE-otail);
  460.                 if(Spy[i] > -1) write(Spy[i], 
  461.                  &Ply[i].io->output[otail], 
  462.                  ohead>otail ? ohead-otail:OBUFSIZE-otail);
  463.                 if(otail > ohead) {
  464.                     n+= write(i, Ply[i].io->output, ohead);
  465.                     if(Spy[i] > -1)
  466.                     write(Spy[i], Ply[i].io->output, ohead);
  467.                 }
  468. /*
  469.                 if(n < buflen(ohead, otail, OBUFSIZE))
  470.                     merror("output_buf", NONFATAL);
  471. */
  472.                 otail = ohead;
  473.                 Ply[i].io->otail = otail;
  474.             }
  475.         }
  476.     }
  477. }
  478.  
  479. /**********************************************************************/
  480. /*                print                      */
  481. /**********************************************************************/
  482.  
  483. /* This function acts just like printf, except it outputs the     */
  484. /* formatted text string to a given socket's output buffer.  The  */
  485. /* socket number is the first parameter.              */
  486.  
  487. void print(fd, fmt, i1, i2, i3, i4, i5, i6)
  488. int     fd;
  489. char     *fmt;
  490. int    i1, i2, i3, i4, i5, i6;
  491. {
  492.     char     msg[2048];
  493.     char    *fmt2;
  494.     int    i = 0, j = 0, k, n, otail, ohead;
  495.     int    num, loc, ind = -1, len, flags = 0;
  496.     int    arg[6];
  497.     char    type;
  498.  
  499.     if(fd == -1 || fd > Tablesize)
  500.         return;
  501.     if(!Ply[fd].io)
  502.         return;
  503.  
  504.     if(Ply[fd].ply) {
  505.         if(F_ISSET(Ply[fd].ply, PDINVI))
  506.             flags |= INV;
  507.         if(F_ISSET(Ply[fd].ply, PDMAGI))
  508.             flags |= MAG;
  509.     }
  510.  
  511.     len = strlen(fmt);
  512.     fmt2 = (char *)malloc(len+1);
  513.     if(!fmt2)
  514.         merror("print", FATAL);
  515.  
  516.     arg[0] = i1; arg[1] = i2; arg[2] = i3; 
  517.     arg[3] = i4; arg[4] = i5; arg[5] = i6;
  518.  
  519.     /* Check for %m, %M, %i and %I and modify arguments as necessary */
  520.     do {
  521.         if(fmt[i] == '%') {
  522.             fmt2[j++] = fmt[i];
  523.             num = 0; k = i;
  524.             do {
  525.                 k++;
  526.                 if((fmt[k] >= 'a' && fmt[k] <= 'z') ||
  527.                    (fmt[k] >= 'A' && fmt[k] <= 'Z') ||
  528.                    fmt[k] == '%') {
  529.                     loc = k;
  530.                     type = fmt[k];
  531.                     break;
  532.                 }
  533.                 else if(fmt[k] >= '0' && fmt[k] <= '9')
  534.                     num = num*10 + fmt[k]-'0';
  535.             } while(k < len);
  536.             if(type == '%') {
  537.                 fmt2[j++] = '%';
  538.                 i++; i++;
  539.                 continue;
  540.             }
  541.             ind++;
  542.             if(type != 'm' && type != 'M' &&
  543.                type != 'i' && type != 'I') {
  544.                 i++;
  545.                 continue;
  546.             }
  547.  
  548.             i = loc + 1;
  549.             fmt2[j++] = 's';
  550.  
  551.             switch(type) {
  552.             case 'm':
  553.                 arg[ind] = (int)crt_str(arg[ind], num, flags);
  554.                 continue;
  555.             case 'M':
  556.                 arg[ind] = (int)crt_str(arg[ind], num, 
  557.                             flags|CAP);
  558.                 continue;
  559.             case 'i':
  560.                 arg[ind] = (int)obj_str(arg[ind], num, flags);
  561.                 continue;
  562.             case 'I':
  563.                 arg[ind] = (int)obj_str(arg[ind], num,
  564.                             flags|CAP);
  565.                 continue;
  566.             }
  567.         }
  568.         fmt2[j++] = fmt[i++];
  569.     } while (i < len);
  570.  
  571.     fmt2[j] = 0;
  572.  
  573.     sprintf(msg, fmt2, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
  574.     free(fmt2);
  575.     n = strlen(msg);
  576.     if(n > 78) {
  577.         delimit(msg);
  578.         n = strlen(msg);
  579.     }
  580.  
  581.     ohead = Ply[fd].io->ohead;
  582.     otail = Ply[fd].io->otail;
  583.  
  584.     for(i=0; i<n; i++) {
  585.         Ply[fd].io->output[ohead] = msg[i];
  586.         ohead = (ohead + 1) % OBUFSIZE;
  587.         if(ohead == otail)
  588.             otail = (otail + 1) % OBUFSIZE;
  589.         if(msg[i] == '\n') {
  590.             Ply[fd].io->output[ohead] = '\r';
  591.             ohead = (ohead + 1) % OBUFSIZE;
  592.             if(ohead == otail)
  593.                 otail = (otail + 1) % OBUFSIZE;
  594.         }
  595.     }
  596.     Ply[fd].io->ohead = ohead;
  597.     Ply[fd].io->otail = otail;
  598. }
  599.  
  600. /**********************************************************************/
  601. /*                handle_commands                  */
  602. /**********************************************************************/
  603.  
  604. /* This function strips out the first command in each player's input */
  605. /* buffer, and then sends that command to the player's next function */
  606. /* of input with the appropriate parameter.                 */
  607.  
  608. void handle_commands()
  609. {
  610.     int    i, j;
  611.     int    itail, ihead;
  612.     char    buf[IBUFSIZE+1];
  613.     for(i=0; i<Tablesize; i++) {
  614.         if(FD_ISSET(i, &Sockets) && Ply[i].io) {
  615.             if(Ply[i].io->commands == -1) {
  616.                 disconnect(i);
  617.                 continue;
  618.             }
  619.             if(!Ply[i].io->commands) continue;
  620.             itail = Ply[i].io->itail;
  621.             ihead = Ply[i].io->ihead;
  622.             if(itail == ihead) continue;
  623.             for(j=0; j<IBUFSIZE; j++) {
  624.                 if(itail == ihead) {
  625.                     buf[j] = 0;
  626.                     break;
  627.                 }
  628.                 if(Ply[i].io->input[itail] == 13 ||
  629.                    Ply[i].io->input[itail] == 10) {
  630.                     itail = (itail + 1) % IBUFSIZE;
  631.                     buf[j] = 0;
  632.                     break;
  633.                 }
  634.                 buf[j] = Ply[i].io->input[itail];
  635.                 itail = (itail + 1) % IBUFSIZE;
  636.             }
  637.             Ply[i].io->itail = itail;
  638.             Ply[i].io->commands--;
  639.             if(Spy[i] > -1) {
  640.                 write(Spy[i], buf, strlen(buf));
  641.                 write(Spy[i], "\n\r", 2);
  642.             }
  643.             (*Ply[i].io->fn) (i, Ply[i].io->fnparam, buf);
  644.         }
  645.     }
  646. }
  647.  
  648. /**********************************************************************/
  649. /*                disconnect                  */
  650. /**********************************************************************/
  651.  
  652. /* This function drops the connection to the player on the socket specified */
  653. /* by the first parameter, clears his spot in the socket bit-array, and     */
  654. /* removes him from the player array by freeing all memory taken by him.    */
  655.  
  656. void disconnect(fd)
  657. int     fd;
  658. {
  659.     int     i;
  660.     etag    *ign, *temp;
  661.     wq_tag    *wq;
  662.  
  663.     close(fd);
  664.     FD_CLR(fd, &Sockets);
  665.  
  666.     Spy[fd] = -1;
  667.  
  668.     if(Ply[fd].io) {
  669.         if(Ply[fd].io->intrpt & 2)
  670.             Numplayers--;
  671.         free(Ply[fd].io);
  672.         Ply[fd].io = 0;
  673.     }
  674.     if(Ply[fd].extr) {
  675.         ign = Ply[fd].extr->first_ignore;
  676.         while(ign) {
  677.             temp = ign;
  678.             ign = ign->next_tag;
  679.             free(temp);
  680.         }
  681.         free(Ply[fd].extr);
  682.         Ply[fd].extr = 0;
  683.     }
  684.     if(Ply[fd].ply) {
  685.         if(F_ISSET(Ply[fd].ply, PSPYON)) {
  686.             for(i=0; i<Tablesize; i++)
  687.                 if(Spy[i] == fd) Spy[i] = -1;
  688.             F_CLR(Ply[fd].ply, PSPYON);
  689.         }
  690.         if(Ply[fd].ply->fd > -1) {
  691.             uninit_ply(Ply[fd].ply);
  692.             save_ply(Ply[fd].ply->name, Ply[fd].ply);
  693.         }
  694.         free_crt(Ply[fd].ply);
  695.         Ply[fd].ply = 0;
  696.     }
  697.     else {
  698.         for(wq = First_wait, i=1; wq; wq = wq->next_tag, i++)
  699.             if(wq->fd == fd) {
  700.                 remove_wait(i);
  701.                 break;
  702.             }
  703.     }
  704.     if(Numwaiting && Numplayers < MAXPLAYERS) {
  705.         i = remove_wait(1);
  706.         if ( i != -1){
  707.         print(i, "%c", 7);
  708.         init_connect(i);
  709.         }
  710.     }
  711. }
  712.  
  713. /**********************************************************************/
  714. /*                broadcast                  */
  715. /**********************************************************************/
  716.  
  717. /* This function broadcasts a message to all the players that are in the */
  718. /* game.  If they have the NO-BROADCAST flag set, then they will not see */
  719. /* it.                                     */
  720.  
  721. void broadcast(fmt, i1, i2, i3, i4, i5, i6)
  722. char     *fmt;
  723. int    i1, i2, i3, i4, i5, i6;
  724. {
  725.     char    fmt2[1024];
  726.     int    i;
  727.  
  728.     strcpy(fmt2, fmt);
  729.     strcat(fmt2, "\n");
  730.     for(i=0; i<Tablesize; i++) {
  731.         if(FD_ISSET(i, &Sockets) && Ply[i].ply)
  732.             if(!F_ISSET(Ply[i].ply, PNOBRD) && Ply[i].ply->fd > -1)
  733.                 print(i, fmt2, i1, i2, i3, i4, i5, i6);
  734.     }
  735. }
  736.  
  737. /**********************************************************************/
  738. /*                broadcast_wiz                  */
  739. /**********************************************************************/
  740.  
  741. /* This function broadcasts a message to all the DM's who are on at the */
  742. /* time.                                */
  743.  
  744. void broadcast_wiz(fmt, i1, i2, i3, i4, i5, i6)
  745. char     *fmt;
  746. int    i1, i2, i3, i4, i5, i6;
  747. {
  748.     char    fmt2[1024];
  749.     int    i;
  750.  
  751.     strcpy(fmt2, fmt);
  752.     strcat(fmt2, "\n");
  753.     for(i=0; i<Tablesize; i++) {
  754.         if(FD_ISSET(i, &Sockets) && Ply[i].ply)
  755.             if(Ply[i].ply->fd > -1 && Ply[i].ply->class >= CARETAKER){
  756.                 ANSI(i,YELLOW);
  757.                 print(i, fmt2, i1, i2, i3, i4, i5, i6); 
  758.                 ANSI(i,WHITE);
  759.             }
  760.     }
  761. }
  762.  
  763. /**********************************************************************/
  764. /*                broadcast_eaves                  */
  765. /**********************************************************************/
  766.  
  767. /* This function broadcasts a message to all the DM's who are on at the */
  768. /* time and have the eavesdropping flag set.                 */
  769.  
  770. void broadcast_eaves(fmt, i1, i2, i3, i4, i5, i6)
  771. char     *fmt;
  772. int    i1, i2, i3, i4, i5, i6;
  773. {
  774.     char    fmt2[1024];
  775.     int    i;
  776.  
  777.     strcpy(fmt2, fmt);
  778.     strcat(fmt2, "\n");
  779.     for(i=0; i<Tablesize; i++) {
  780.         if(FD_ISSET(i, &Sockets) && Ply[i].ply)
  781.             if(Ply[i].ply->fd > -1 &&
  782.                Ply[i].ply->class >= CARETAKER && 
  783.                F_ISSET(Ply[i].ply, PEAVES))
  784.                 print(i, fmt2, i1, i2, i3, i4, i5, i6);
  785.     }
  786. }
  787.  
  788. /**********************************************************************/
  789. /*                broadcast_rom                  */
  790. /**********************************************************************/
  791.  
  792. /* This function outputs a message to everyone in the room specified */
  793. /* by the integer in the second parameter.  If the first parameter   */
  794. /* is greater than -1, then if the player specified by that file     */
  795. /* descriptor is present in the room, he is not given the message    */
  796.  
  797. void broadcast_rom(ignore, rm, fmt, i1, i2, i3, i4, i5, i6)
  798. int    ignore, rm;
  799. char     *fmt;
  800. int    i1, i2, i3, i4, i5, i6;
  801. {
  802.     char    fmt2[1024];
  803.     int    i;
  804.  
  805.     strcpy(fmt2, fmt);
  806.     strcat(fmt2, "\n");
  807.     for(i=0; i<Tablesize; i++) {
  808.         if(FD_ISSET(i, &Sockets) && Ply[i].ply)
  809.             if(Ply[i].ply->rom_num == rm && Ply[i].ply->fd > -1
  810.                && i != ignore )
  811.                 print(i, fmt2, i1, i2, i3, i4, i5, i6);
  812.     }
  813. }
  814.  
  815. /**********************************************************************/
  816. /*                broadcast_rom2                  */
  817. /**********************************************************************/
  818.  
  819. /* This function is the same as broadcast_rom except that it will ignore */
  820. /* two people in a room.                         */
  821.  
  822. void broadcast_rom2(ignore1, ignore2, rm, fmt, i1, i2, i3, i4, i5, i6)
  823. int    ignore1, ignore2, rm;
  824. char     *fmt;
  825. int    i1, i2, i3, i4, i5, i6;
  826. {
  827.     char    fmt2[1024];
  828.     int    i;
  829.  
  830.     strcpy(fmt2, fmt);
  831.     strcat(fmt2, "\n");
  832.     for(i=0; i<Tablesize; i++) {
  833.         if(FD_ISSET(i, &Sockets) && Ply[i].ply)
  834.             if(Ply[i].ply->rom_num == rm && Ply[i].ply->fd > -1
  835.                && i != ignore1 && i != ignore2)
  836.                 print(i, fmt2, i1, i2, i3, i4, i5, i6);
  837.     }
  838. }
  839.  
  840. /************************************************************************/
  841. /*                inetname                */
  842. /************************************************************************/
  843.  
  844. /* This function returns the internet address of the address structure    */
  845. /* passed in as the first parameter.                    */
  846.  
  847. char *inetname(in)
  848. struct in_addr in;
  849. {
  850.     register char *cp=0;
  851.     static char line[50];
  852.     struct hostent *hp;
  853.     struct netent *np;
  854.     static char domain[81];
  855.     static int first = 1;
  856.     int net, lna;
  857.  
  858. #ifdef GETHOSTBYNAME
  859.     if (first) {
  860.         first = 0;
  861.         if (gethostname(domain, 80) == 0 &&
  862.             (cp = index(domain, '.')))
  863.             (void) strcpy(domain, cp + 1);
  864.         else
  865.             domain[0] = 0;
  866.     }
  867.     cp = 0;
  868.     if (in.s_addr != INADDR_ANY) {
  869.         net = inet_netof(in);
  870.         lna = inet_lnaof(in);
  871.  
  872.         if (lna == INADDR_ANY) {
  873.             np = getnetbyaddr(net, AF_INET);
  874.             if (np)
  875.                 cp = np->n_name;
  876.         }
  877.         if (cp == 0) {
  878.             hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
  879.             if (hp) {
  880.                 if ((cp = index(hp->h_name, '.')) &&
  881.                     !strcmp(cp + 1, domain))
  882.                     *cp = 0;
  883.                 cp = hp->h_name;
  884.             }
  885.         }
  886.     }
  887. #endif
  888.     if (in.s_addr == INADDR_ANY)
  889.         strcpy(line, "*");
  890.     else if (cp)
  891.         strcpy(line, cp);
  892.     else {
  893.         in.s_addr = ntohl(in.s_addr);
  894. #define C(x)    ((x) & 0xff)
  895.         sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  896.             C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
  897.     }
  898.     return (line);
  899. }
  900.  
  901. /************************************************************************/
  902. /*                add_wait                */
  903. /************************************************************************/
  904.  
  905. /* This function adds the descriptor in the first parameter to the    */
  906. /* waiting queue.                            */
  907.  
  908. void add_wait(fd)
  909. int    fd;
  910. {
  911.     wq_tag    *new_wq, *wq;
  912.  
  913.     new_wq = (wq_tag *)malloc(sizeof(wq_tag));
  914.     new_wq->next_tag = 0;
  915.     new_wq->fd = fd;
  916.  
  917.     if(!First_wait) {
  918.         First_wait = new_wq;
  919.         Numwaiting = 1;
  920.     }
  921.     else {
  922.         wq = First_wait;
  923.         while(wq->next_tag)
  924.             wq = wq->next_tag;
  925.         wq->next_tag = new_wq;
  926.         Numwaiting++;
  927.     }
  928.     print(fd, "The game is full.\nYou are player #%d in the waiting queue.\n", Numwaiting);
  929. }
  930.  
  931. /************************************************************************/
  932. /*                remove_wait                */
  933. /************************************************************************/
  934.  
  935. /* This function removes the i'th player from the waiting queue.    */
  936.  
  937. int remove_wait(i)
  938. int    i;
  939. {
  940.     int    j, fd;
  941.     wq_tag    *wq, *prev;
  942.     long    t;
  943.     char     str[50];
  944.  
  945.     wq = First_wait;
  946.  
  947. /* write is being used here to check to see if the given
  948.   file desc. is still valid.  Theorically, only one write is
  949.   needed, but for some reason 2 writes are needed */
  950.  
  951.  write(wq->fd," ",1);
  952.         if(i == 1) {
  953.                 if (write(wq->fd,"\n",1) == -1){
  954.                 fd = -1;
  955.         }
  956.                 else
  957.                 fd = wq->fd;
  958.                 First_wait = wq->next_tag;
  959.         }
  960.     else {
  961.         for(j=1; j<i; j++) {
  962.             prev = wq;
  963.             wq = wq->next_tag;
  964.         }
  965.         fd = wq->fd;
  966.         prev->next_tag = wq->next_tag;
  967.     }
  968.  
  969.     free(wq);
  970.     Numwaiting--;
  971.  
  972.     for(wq=First_wait, j=1; wq; wq=wq->next_tag, j++)
  973.         if(j >= i) print(wq->fd, "You are player #%d in the waiting queue.\n", j);
  974.  
  975.     output_buf();
  976.     return(fd);
  977. }
  978.  
  979. void waiting(fd, param, str)
  980. int    fd;
  981. int    param;
  982. char    *str;
  983. {
  984.     RETURN(fd, waiting, 1);
  985. }
  986.  
  987. /************************************************************************/
  988. /*                child_died                */
  989. /************************************************************************/
  990.  
  991. /* This function gets called when a SIGCHLD signal is sent to the    */
  992. /* program.                                */
  993.  
  994. void child_died()
  995. {
  996.     Deadchildren++;
  997.     signal(SIGCHLD, child_died);
  998. }
  999.  
  1000. /************************************************************************/
  1001. /*                reap_children                */
  1002. /************************************************************************/
  1003.  
  1004. /* This program goes through and kills off (waits for) each child    */
  1005. /* that has completed processing to avoid zombie processes.        */
  1006. /* If the child was an authentication process, then the information    */
  1007. /* it returned is looked up in the file it saved.            */
  1008.  
  1009. void reap_children()
  1010. {
  1011.     int pid, i, found, status;
  1012.     char filename[127], userid[80], address[80], timestr[80];
  1013.     FILE *fp;
  1014.     long t;
  1015.  
  1016.     t = time(0);
  1017.     strcpy(timestr, (char *)ctime(&t));
  1018.     timestr[strlen(timestr)-1] = 0;
  1019.  
  1020.     while(Deadchildren > 0) {
  1021.         Deadchildren--;
  1022.         found = -1;
  1023.         pid = wait(&status);
  1024.         sprintf(filename, "%s/auth/lookup.%d", LOGPATH, pid);
  1025.         for(i=0; i<Tablesize; i++) {
  1026.             if(Ply[i].io && Ply[i].io->lookup_pid == pid) {
  1027.                 found = i;
  1028.                 break;
  1029.             }
  1030.         }
  1031.         if(found < 0) {
  1032.             if(file_exists(filename)) unlink(filename);
  1033.             continue;
  1034.         }
  1035.         fp = fopen(filename, "r");
  1036.         if(!fp) continue;
  1037.         fscanf(fp, "%s %s", userid, address);
  1038.         if(strlen(userid))
  1039.             userid[8] = 0;
  1040.         if(strlen(address))
  1041.             address[39] = 0;
  1042.         fclose(fp);
  1043.         unlink(filename);
  1044.         strcpy(Ply[found].io->userid, userid);
  1045.         logf("%s: %s@%s (%s@%s) connected.\n", timestr,
  1046.             userid, address, userid, Ply[found].io->address);
  1047.         if(strcmp(address, "UNKNOWN"))
  1048.             strcpy(Ply[found].io->address, address);
  1049.     }
  1050.  
  1051.     /* just in case, kill off any zombies */
  1052.     wait4(-1, &status, WNOHANG, (struct rusage *)0);
  1053.  
  1054. }
  1055.